package com.wsl.HealthChallenge.controllers;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.Map.Entry;
import java.util.logging.Level;

import javax.jdo.JDOHelper;
import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.google.appengine.api.labs.taskqueue.Queue;
import com.google.appengine.api.labs.taskqueue.TaskOptions;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.wsl.HealthChallenge.models.ContestEntry;
import com.wsl.HealthChallenge.models.ContestType;
import com.wsl.HealthChallenge.models.UserStats;
import com.wsl.HealthChallenge.utils.DataStorageUtils;
import com.wsl.HealthChallenge.utils.PMF;
import com.wsl.HealthChallenge.utils.Utils;

/**
 * 
 * @author mark
 */
@Controller
public class DebugController {
    @RequestMapping("/{challengeId}/debug")
    public ModelAndView debugHandler(@PathVariable String challengeId,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        StringBuilder builder = new StringBuilder();

        UserService userService = UserServiceFactory.getUserService();
        String thisURL = request.getRequestURI();
        if (userService.isUserLoggedIn()) {
            builder.append("<p>Your userId: ");
            builder.append(userService.getCurrentUser().getUserId());
            builder.append("</p>");
            builder.append("<p>Hello, ");
            builder.append(request.getUserPrincipal().getName());
            builder.append("!  You can <a href=\"");
            builder.append(userService.createLogoutURL(thisURL));
            builder.append("\">sign out</a>.</p>");
        } else {
            builder.append("<p>Please <a href=\"");
            builder.append(userService.createLoginURL(thisURL));
            builder.append("\">sign in</a>.</p>");
        }
        builder.append("<p><a href=\"/");
        builder.append(challengeId);
        builder.append("/debug/add/100");
        builder.append("\">add 100 participants with -1 score</a>.</p>");

        builder.append("<p><a href=\"/");
        builder.append(challengeId);
        builder.append("/debug/add/100?randomScore=1");
        builder.append("\">add 100 participants with random score</a>.</p>");

        builder.append("<p><a href=\"/");
        builder.append(challengeId);
        builder.append("/debug/clear");
        builder.append("\">clear all participants</a>.</p>");

        builder.append("<p><a href=\"/task/updatescore/");
        builder.append(challengeId);
        builder.append("\">update score</a>.</p>");

        builder.append("<p><a href=\"/");
        builder.append(challengeId);
        builder.append("/debug/check");
        builder.append("\">check how many have -1 zero</a>.</p>");

        response.getWriter().println(builder.toString());
        return null;
    }

    /**
     * Adds 100 fake users to the given contest.
     * 
     * @param challengeId
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping("/{challengeId}/debug/add/{num}")
    public ModelAndView debugAdd100Handler(
            @PathVariable String challengeId, @PathVariable int num,
            @RequestParam(value="randomScore", defaultValue="0") boolean useRandomScore,
            HttpServletRequest request, HttpServletResponse response) throws Exception {

        ContestEntry challenge = DataStorageUtils.getContest(challengeId);
        if (challenge == null) {
            response.getWriter().println("Challenge does not exist.");
            return null;
        }

        Map<String, UserStats> userStats = challenge.getUserStats();
        String testToken = "testToken";
        if (!userStats.isEmpty()) {
            testToken = userStats.values().iterator().next().getGoogleHealthSessionToken();
        }

        Random rand = new Random();
        for(int i = 0; i < num; i++) {
            float score = -1.f;
            if (useRandomScore) {
                score = rand.nextFloat() * 1000;
            }
	        userStats.put("6666" + i, new UserStats("TestName" + i, score, testToken));
        }

        JDOHelper.makeDirty(challenge, "userStats"); 
        DataStorageUtils.insertOrUpdateContest(challenge);

        response.getWriter().println("<p>Succesfully added " + num + " test users.</p>");
        return null;
    }

    @RequestMapping("/{challengeId}/debug/clear")
    public ModelAndView debugAdd100Handler(@PathVariable String challengeId,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        ContestEntry challenge = DataStorageUtils.getContest(challengeId);
        if (challenge == null) {
            response.getWriter().println("Challenge does not exist.");
            return null;
        }

        Map<String, UserStats> userStats = challenge.getUserStats();
        userStats.clear();
        JDOHelper.makeDirty(challenge, "userStats"); 
        DataStorageUtils.insertOrUpdateContest(challenge);

        response.getWriter().println("<p>Succesfully cleared all users.</p>");
        return null;
    }

    @RequestMapping("/{challengeId}/debug/check")
    public ModelAndView debugCheckNumZeroScoreHandler(
            @PathVariable String challengeId,
            HttpServletRequest request, HttpServletResponse response) throws Exception {

        ContestEntry challenge = DataStorageUtils.getContest(challengeId);
        if (challenge == null) {
            response.getWriter().println("Challenge does not exist.");
            return null;
        }

        int numUsersWithZeroScore = 0;
        Map<String, UserStats> allUserStats = challenge.getUserStats();
        for (Entry<String, UserStats> entry : allUserStats.entrySet()) {
            UserStats userStats = entry.getValue();
            if (userStats.getScore() < 0.f) {
                numUsersWithZeroScore++;
            }
        }
        response.getWriter().println("<p>#user with -1 score: " + numUsersWithZeroScore + "</p>");
        return null;
    }

    @RequestMapping("/{challengeId}/debug/addAdmin")
    public ModelAndView debugAddAdminEmailHandler(
            @PathVariable String challengeId,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (!Utils.ensureUserLoggedIn(request, response)) {
            return null;
        }
        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();

        PersistenceManager pm = PMF.get().getPersistenceManager();
        try {
            ContestEntry challenge = null;
            pm.currentTransaction().begin();
            try {
                challenge = pm.getObjectById(ContestEntry.class, challengeId);
                challenge.addAdminUser(user.getUserId());
            } catch (JDOObjectNotFoundException e) {
            }
            pm.currentTransaction().commit();
        //} catch (Exception e) {
        //    return false;
        } finally {
            if (pm.currentTransaction().isActive()) {
                pm.currentTransaction().rollback();
            }
        }
        response.sendRedirect("/"+challengeId+"/admin");
        return null;
    }

    @RequestMapping("/{challengeId}/debug/update/{userId}")
    public ModelAndView debugUpdateUserScoreHandler(
            @PathVariable String challengeId,
            @PathVariable String userId,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        ContestEntry challenge = DataStorageUtils.getContest(challengeId);
        if (challenge == null) {
            response.getWriter().println("Challenge does not exist.");
            return null;
        }

        Queue queue = UpdateScoreController.getUpdateScoreQueue();
        Map<String, UserStats> allUserStats = challenge.getUserStats();
        UserStats stats = allUserStats.get(userId);
        UpdateScoreController.addUpdateParticipantTask(challengeId, challenge,
                userId, stats, queue);
        return null;
    }
    
    @RequestMapping("/{challengeId}/debug/updateVerbose/{userId}")
    public ModelAndView debugUpdateUserScoreHandlerVerbose(
            @PathVariable String challengeId,
            @PathVariable String userId,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        ContestEntry challenge = DataStorageUtils.getContest(challengeId);
        if (challenge == null) {
            response.getWriter().println("Challenge does not exist.");
            return null;
        }

        Queue queue = UpdateScoreController.getUpdateScoreQueue();
        Map<String, UserStats> allUserStats = challenge.getUserStats();
        UserStats stats = allUserStats.get(userId);
        
        ServletContext servletContext = request.getSession().getServletContext();
        GoogleHealthCalorieRequester requester = new GoogleHealthCalorieRequester(servletContext);

        ContestType contestType = 
            ContestType.getFromStringRepresentation(challenge.getType().stringRepresentation);
//        String startTimestamp = String.valueOf(challenge.getStartDate().getTime());
//        String endTimestamp = String.valueOf(challenge.getEndDate().getTime());
//        Date startDate = new Date(startTimestamp);
//        Date endDate = new Date(endTimestamp);

        Date startDate = challenge.getStartDate();
        Date endDate = challenge.getEndDate();

        requester.setVerbose(true);
        int scoreValue = requester.getTrackerValue(request, response,
                stats.getGoogleHealthSessionToken(), contestType.googleHealthTracker,
                startDate, endDate);
        UpdateScoreController.log.log(Level.SEVERE, "verbose:scoreValue:" + scoreValue);
        return null;
    }

    @RequestMapping("/debug/profile")
    public ModelAndView showDebugProfileHandler(
            HttpServletRequest request, 
            HttpServletResponse response) throws Exception {
        if (!Utils.ensureUserLoggedIn(request, response)) {
            return null;
        }
        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();
        response.sendRedirect("/debug/profile/" + user.getUserId());
        return null;
    }

    @RequestMapping("/debug/profile/{userId}")
    public ModelAndView updateScoreHandler(
            @PathVariable String userId,
            HttpServletRequest request, 
            HttpServletResponse response) throws Exception {
        PersistenceManager pm = PMF.get().getPersistenceManager();
        Query query = pm.newQuery(ContestEntry.class);
        List<ContestEntry> results = (List<ContestEntry>) query.execute();

        StringBuilder builder = new StringBuilder("<p>Profile of userId:" + userId + "</p>");
        builder.append("<p>Participates in following challenges:</p>");
        for (ContestEntry challenge : results) {
            UserStats stats = challenge.getUserStats().get(userId);
            if (stats != null) {
                builder.append("<p>");
                builder.append("<a href=\"" + challenge.getId() + "\">" + challenge.getName() + "</a>");
                builder.append("</br> Name:" + stats.getName());
                builder.append("</br> score:" + stats.getScore());
                builder.append("</br> Token:" + stats.getGoogleHealthSessionToken());
                builder.append("</br> Timestamp:" + stats.getLastUpdateTimestamp());
                builder.append("</p>");
            }
        }
        response.getWriter().print(builder.toString());
        return null;
    }

    @RequestMapping("/debug/test1")
    public ModelAndView debugTest1(
            HttpServletRequest request, 
            HttpServletResponse response) throws Exception {
        Set<ValueAndDate> uniqueEntries = new HashSet<ValueAndDate>();
        uniqueEntries.add(new ValueAndDate(1000000, 1111));
        uniqueEntries.add(new ValueAndDate(1000000, 1111));
        uniqueEntries.add(new ValueAndDate(1000000, 2222));
        uniqueEntries.add(new ValueAndDate(1000000, 2222));
        uniqueEntries.add(new ValueAndDate(1000000, 3333));
        uniqueEntries.add(new ValueAndDate(4000000, 3333));

        StringBuilder builder = new StringBuilder();
        builder.append("#uniqe entries:" + uniqueEntries.size()+"\n");
        for (ValueAndDate entry : uniqueEntries) {
            builder.append(entry.collectionDate);
            builder.append(": ");
            builder.append(entry.value);
            builder.append("\n");
        }

        response.getWriter().print(builder.toString());
        return null;
    }
 }